#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

#include "hv_mem_pool.h"

#define RANDOM_VALUE(x, y)		((random() % (((y)-(x)) * 10)) / 10 + (x))

static	void	do_interactive();
static	void	*get_address(void);
static	long	hex_to_long(const char *str);
static  void    do_random();

#define RANDCOUNT   (1<<30)
#define RANDRANGE1  (0)
#define RANDRANGE2  (1<<11)

int main(int argc, char** argv)
{
    char ind = 'R';
    if(argc >= 2 && argv[1][0] == 'I')
        ind = 'I';

    if(ind == 'I')
        do_interactive();
    else
        do_random();

    return 0;
}

static  void    do_random()
{
    hv_mpool_t* mp_p;
    int ret;
    unsigned long rand_num;
    int i;
    void *pp, *prev, *hd;
    clock_t clk1, clk2;
    time_t tt;

    tt = time(0);

    if(fork()){
    /* -- Parent normal alloc --- */
    srandom(tt);
    clk1 = clock();
    for(i=0; i<RANDCOUNT; i++)
    {
        rand_num = RANDOM_VALUE(RANDRANGE1, RANDRANGE2);
        pp = malloc(rand_num);
        free(pp);
    }
    clk2 = clock();
    printf("normal time 1- %d, 2- %d, diff- %d\n", clk1, clk2, clk2-clk1);
    /* ------ */
    }else{
    /* **** Child memory pool *** */
    srandom(tt);
    clk1 = clock();
    mp_p = hv_mpool_create(&ret);
    for(i=0; i<RANDCOUNT; i++)
    {
        rand_num = RANDOM_VALUE(RANDRANGE1, RANDRANGE2);
        pp = hv_mpool_alloc(mp_p, rand_num, &ret);
        if(ret != HV_MP_ERR_NONE)
        {
            hv_mpool_strerr(ret);
            break;
        }
        hv_mpool_free(mp_p, pp, &ret);
        if(ret != HV_MP_ERR_NONE)
        {
            hv_mpool_strerr(ret);
            break;
        }
    }
    hv_mpool_destroy(mp_p, &ret);
    if(ret != HV_MP_ERR_NONE)
    {
        hv_mpool_strerr(ret);
    }
    clk2 = clock();
    printf("new time 1- %d, 2- %d, diff- %d\n", clk1, clk2, clk2-clk1);
    /* ******* */
    }
}

static	long	hex_to_long(const char *str)
{
  long		ret;
  const char	*str_p = str;

  /* strip off spaces */
  for (; *str_p == ' ' || *str_p == '\t'; str_p++) {
  }

  /* skip a leading 0[xX] */
  if (*str_p == '0' && (*(str_p + 1) == 'x' || *(str_p + 1) == 'X')) {
    str_p += 2;
  }

  for (ret = 0;; str_p++) {
    if (*str_p >= '0' && *str_p <= '9') {
      ret = ret * 16 + (*str_p - '0');
    }
    else if (*str_p >= 'a' && *str_p <= 'f') {
      ret = ret * 16 + (*str_p - 'a' + 10);
    }
    else if (*str_p >= 'A' && *str_p <= 'F') {
      ret = ret * 16 + (*str_p - 'A' + 10);
    }
    else {
      break;
    }
  }

  return ret;
}

static	void	*get_address(void)
{
  char	line[80];
  void	*pnt;

  do {
    (void)printf("Enter a hex address: ");
    if (fgets(line, sizeof(line), stdin) == NULL) {
      return NULL;
    }
  } while (line[0] == '\0');

  pnt = (void *)hex_to_long(line);

  return pnt;
}

static	void	do_interactive()
{
  hv_mpool_t *pool;
  int		len, ret;
  char		line[128], *line_p;
  void		*pnt, *new_pnt;

  (void)printf("Mpool test program.  Type 'help' for assistance.\n");
  pool = hv_mpool_create(&ret);
  for (;;) {
    (void)printf("> ");
    if (fgets(line, sizeof(line), stdin) == NULL) {
      break;
    }
    line_p = strchr(line, '\n');
    if (line_p != NULL) {
      *line_p = '\0';
    }

    len = strlen(line);
    if (len == 0) {
      continue;
    }

    if (strncmp(line, "?", len) == 0
	|| strncmp(line, "help", len) == 0) {
      (void)printf("\thelp      - print this message\n\n");

      (void)printf("\tmalloc    - allocate memory\n");
      (void)printf("\tcalloc    - allocate/clear memory\n");
      (void)printf("\trealloc    - resize memory\n");
      (void)printf("\tfree      - deallocate memory\n\n");

      (void)printf("\tclear     - clear the pool\n");
      (void)printf("\toverwrite - overwrite some memory to test errors\n");
      (void)printf("\trandom    - randomly execute a number of [de] allocs\n");

      (void)printf("\tquit      - quit this test program\n");
      continue;
    }

    if (strncmp(line, "quit", len) == 0) {
      break;
    }

    if (strncmp(line, "malloc", len) == 0) {
      int	size;

      (void)printf("How much to malloc: ");
      if (fgets(line, sizeof(line), stdin) == NULL) {
	break;
      }
      size = atoi(line);
      pnt = hv_mpool_alloc(pool, size, &ret);
      if (pnt == NULL) {
	(void)printf("malloc(%d) failed: %s\n", size, hv_mpool_strerr(ret));
      }
      else {
	(void)printf("malloc(%d) returned '%#lx'\n", size, (long)pnt);
      }
      continue;
    }

    if (strncmp(line, "calloc", len) == 0) {
      int	size;

      (void)printf("How much to calloc: ");
      if (fgets(line, sizeof(line), stdin) == NULL) {
	break;
      }
      size = atoi(line);
      pnt = hv_mpool_calloc(pool, size, &ret);
      if (pnt == NULL) {
	(void)printf("calloc(%d) failed: %s\n", size, hv_mpool_strerr(ret));
      }
      else {
	(void)printf("calloc(%d) returned '%#lx'\n", size, (long)pnt);
      }
      continue;
    }

    if (strncmp(line, "realloc", len) == 0) {
      int	size, old_size;

      pnt = get_address();

      (void)printf("New size of allocation: ");
      if (fgets(line, sizeof(line), stdin) == NULL) {
	break;
      }
      size = atoi(line);

      new_pnt = hv_mpool_realloc(pool, pnt, size, &ret);
      if (new_pnt == NULL) {
	(void)printf("resize(%#lx, %d) failed: %s\n",
		     (long)pnt, size, hv_mpool_strerr(ret));
      }
      else {
	(void)printf("resize(%#lx, %d) returned '%#lx'\n",
		     (long)pnt, size, (long)new_pnt);
      }
      continue;
    }

    if (strncmp(line, "free", len) == 0) {
      int	old_size;

      pnt = get_address();

      hv_mpool_free(pool, pnt, &ret);
      if (ret != HV_MP_ERR_NONE) {
	(void)fprintf(stderr, "free failed: %s\n", hv_mpool_strerr(ret));
      }
      continue;
    }

    if (strncmp(line, "clear", len) == 0) {
/*     ret = hv_mpool_clear(pool);
      if (ret == HV_MP_ERR_NONE) {
	(void)fprintf(stderr, "clear succeeded\n");
      }
      else {
	(void)fprintf(stderr, "clear failed: %s\n", hv_mpool_strerr(ret));
      }*/
      printf("do nothing\n");
      continue;
    }

    if (strncmp(line, "overwrite", len) == 0) {
      char	*overwrite = "OVERWRITTEN";

      pnt = get_address();
      memcpy((char *)pnt, overwrite, strlen(overwrite));
      (void)printf("Done.\n");
      continue;
    }

    /* do random heap hits */
    if (strncmp(line, "random", len) == 0) {
      int	iter_n;
      /*
      (void)printf("How many iterations[%d]: ", default_iter_n);
      if (fgets(line, sizeof(line), stdin) == NULL) {
	break;
      }
      if (line[0] == '\0' || line[0] == '\n') {
	iter_n = default_iter_n;
      }
      else {
	iter_n = atoi(line);
      }

      do_random(pool, iter_n);*/
      printf("do nothing\n");
      continue;
    }

    (void)printf("Unknown command '%s'.  Type 'help' for assistance.\n", line);
  }
  hv_mpool_destroy(pool, &ret);
}

